#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>

#include "thread_pool.h"
int total_file;

int copyfile(int fd_src, int fd_dst)
{
	char buf[BUFSIZE];
	int nread, nwrite, ntotal=0;

	while(1)
	{
		bzero(buf, BUFSIZE);
		nread = read(fd_src, buf, BUFSIZE);
		if(nread == 0)
			break;
		else if(nread == -1)
		{
			perror("read error");
			return -1;
		}
		
		char *p = buf;
		while(nread > 0)
		{
			nwrite = write(fd_dst, p, nread);
			nread -= nwrite;
			p += nwrite;
			ntotal += nwrite;
		}
	}

// #ifdef DEBUG
// 			printf("搬运完成 [%d] 字节 \n", ntotal);
// #endif

	return ntotal;
}

void *mytask(void *arg)
{
	int fd[2];
	fd[0] = ((int *)arg)[0];
	fd[1] = ((int *)arg)[1];

	copyfile(fd[0], fd[1]);

	close(fd[0]);
	close(fd[1]);

	free(arg);

	return NULL;
}

void copydir(thread_pool *pool,
		const char *dir_src, const char *dir_dst)
{
	char abs_ori[PATHSIZE] = {0};
	char abs_src[PATHSIZE] = {0};
	char abs_dst[PATHSIZE] = {0};

	getcwd(abs_ori, PATHSIZE);

	chdir(dir_src);
	getcwd(abs_src, PATHSIZE);

	chdir(abs_ori);
	mkdir(dir_dst, 0777);
	chdir(dir_dst);
	getcwd(abs_dst, PATHSIZE);

	
	DIR *dp_src;
	dp_src = opendir(abs_src);
	
	struct dirent *ep;
	struct stat *file_info;
	while(1)
	{
		chdir(abs_src);

		ep = readdir(dp_src);
		if(ep == NULL)
			break;
		else if(!strcmp(ep->d_name, ".") ||
			!strcmp(ep->d_name, ".."))
			continue;

		file_info = calloc(1, sizeof(struct stat));
		stat(ep->d_name, file_info);
		
		char src_path[PATHSIZE] = {0};
		char dst_path[PATHSIZE] = {0};

		if(S_ISDIR(file_info->st_mode))
		{
			chdir(abs_src);
			chdir(ep->d_name);
			getcwd(src_path, PATHSIZE);

			chdir(abs_dst);
			mkdir(ep->d_name, 0777);
			chdir(ep->d_name);
			getcwd(dst_path, PATHSIZE);

#ifdef DEBUG
			printf("正在搬运 [%s]==>[%s] \n", src_path, dst_path);
#endif

			/* copy sub-directory recursively */
			copydir(pool, src_path, dst_path);
		}
		else if(S_ISREG(file_info->st_mode))
		{
			int *fd = calloc(2, sizeof(int));

			while(1)
			{
				fd[0] = open(ep->d_name, O_RDONLY);
		
				chdir(abs_dst);
				fd[1] = open(ep->d_name,
						O_WRONLY|O_CREAT|O_TRUNC,
						0644);

				if(fd[0] == -1  && errno == ENFILE)
					add_thread(pool, 10);
				else
					break;
			}
	
#ifdef DEBUG
			snprintf(src_path, PATHSIZE, "%s/%s", abs_src, ep->d_name);
			snprintf(dst_path, PATHSIZE, "%s/%s", abs_dst, ep->d_name);
			printf("正在搬运 [%s](%d)==>[%s](%d) \n", src_path, fd[0], dst_path, fd[1]);
			printf("已搬运 %d 个文件\n", total_file++);
#endif
			add_task(pool, mytask, (void *)fd);
		}
		else
		{
			char type;
			switch(file_info->st_mode & S_IFMT)
			{
			case S_IFBLK: type='b'; break;
			case S_IFCHR: type='c'; break;
			case S_IFIFO: type='p'; break;
			case S_IFLNK: type='l'; break;
			case S_IFSOCK: type='s'; break;
			}
			printf("略过特殊文件[('%c')%s/%s]\n", type, abs_src, ep->d_name);
		}
	}
	free(file_info);
}

int main(int argc, char **argv)
{
	if(argc != 3)
		exit(0);

	// 1, initialize the pool
	thread_pool *pool = malloc(sizeof(thread_pool));
	init_pool(pool, 10);

	struct stat *file_info = calloc(1, sizeof(struct stat));
	stat(argv[1], file_info);

	// 2, throw tasks
	if(S_ISREG(file_info->st_mode))
	{
		int fd[2];
		fd[0] = open(argv[1], O_RDONLY);
		fd[1] = open(argv[2], O_CREAT|O_WRONLY|O_TRUNC, 0644);
		add_task(pool, mytask, (void *)fd);
	}
	else if(S_ISDIR(file_info->st_mode))
	{
		copydir(pool, argv[1], argv[2]);
	}
	else
		printf("file format is NOT supported.\n");

	// 3, destroy the pool
	destroy_pool(pool);
	pthread_exit(NULL);
}
